package com.starxg.m3u8.utils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

/**
 * EncryptUtils
 * 
 * @author huangxingguang@lvmama.com
 * @date 2020-05-30 15:50
 */
public class EncryptUtils {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static ByteBuffer decrypt(String key, ByteBuffer content) {
        return decrypt(key, content, null);
    }

    public static ByteBuffer decrypt(String key, ByteBuffer content, byte[] iv) {
        return decrypt(key.getBytes(), content, iv);
    }

    public static ByteBuffer decrypt(byte[] key, ByteBuffer content, byte[] iv) {
        try {
            Cipher decrypt = cipher(key, Cipher.DECRYPT_MODE, iv);
            ByteBuffer out = ByteBuffer.allocateDirect(content.limit());
            decrypt.doFinal(content, out);
            out.flip();
            return out;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ByteBuffer decrypt(byte[] key, FileChannel fileChannel) throws IOException {
        return decrypt(key, fileChannel, null);
    }

    public static ByteBuffer decrypt(byte[] key, FileChannel fileChannel, byte[] iv) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocateDirect((int) fileChannel.size());
        fileChannel.read(buffer);
        buffer.flip();
        return decrypt(key, buffer, iv);
    }


    private static Cipher cipher(byte[] key, int mode, String iv) throws Exception {
        return cipher(key, mode, iv(iv));
    }

    private static Cipher cipher(byte[] key, int mode, byte[] iv) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        IvParameterSpec spec = new IvParameterSpec(ObjectUtils.defaultIfNull(iv, new byte[16]));
        cipher.init(mode, keySpec, spec);
        return cipher;
    }

    public static byte[] iv(String iv) {
        byte[] ivs = null;
        if (StringUtils.isNotBlank(iv)) {
            if (iv.startsWith("0x")) {
                ivs = Hex.decode(iv.substring(2));
            } else {
                ivs = iv.getBytes();
            }
        }

        if (ivs == null || ivs.length != 16) {
            ivs = new byte[16];
        }
        return ivs;
    }

}
